package com.xinsoft.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.toolkit.StringUtils;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.*;
import com.xinsoft.entity.po.*;
import com.xinsoft.service.*;
import com.xinsoft.mapper.MesCraftMapper;
import com.xinsoft.utils.ExcelUtils;
import com.xinsoft.validator.ValidatorUtils;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author lijie
 * @description 针对表【mes_craft(工艺路线)】的数据库操作Service实现
 * @createDate 2023-07-20 10:25:16
 */
@Service
public class MesCraftServiceImpl extends ServiceImpl<MesCraftMapper, MesCraft>
        implements MesCraftService {

    @Resource
    MesCraftMapper craftMapper;

    @Resource
    MesCraftProcessRefService processRefService;

    @Resource
    MesProcessTestpointService testpointService;

    @Resource
    MesCarftTeamUserService carftTeamUserService;

    @Resource
    MesCraftDeviceService craftDeviceService;

    @Resource
    MesCraftCheckRefService craftCheckRefService;

    @Resource
    MesProcessTestpointService mesProcessTestpointService;

    @Resource
    MesCraftMaterialRefService craftMaterialRefService;

    @Resource
    MesCraftMaterialService mesCraftMaterialService;

    @Resource
    MesDocumentService mesDocumentService;

    @Resource
    SysFileHisService sysFileHisService;

    @Resource
    MesTeamUserRefService mesTeamUserRefService;

    @Resource
    SysUserService sysUserService;

    @Resource
    MesProcessService mesProcessService;

    @Override
    public Map<String, Object> getInfoById(Integer id) {
        Map<String, Object> map = new HashMap<>();
        // 拿基础数据
        MesCraft mesCraft = craftMapper.selectById(id);
        map.put("mesCraft", mesCraft);
        return map;
    }

    @Override
    public void edit(MesCraftDTO mesCraftDTO) {
        craftMapper.updateById(mesCraftDTO);
        // 删除子集集合
        this.deleteChildren(mesCraftDTO);
        // 重新新增
        this.saveChildren(mesCraftDTO);
    }

    @Override
    public void create(MesCraftDTO mesCraftDTO) {
        craftMapper.insert(mesCraftDTO);
        this.saveChildren(mesCraftDTO);
    }

    @Override
    public Object findPageListByParam(MesCraftParam param) {
        //分页
        Page<MesCraft> page = new Page<MesCraft>(param.getCurrentPage(), param.getPageSize());
        IPage<MesCraft> resultPage = craftMapper.findListByParam(page, param);
        //返回值
        return resultPage;
    }

    private void saveMesCraftDocumentList(MesCraftProcessRefDTO mesCraftUnionDTO) {
        if (mesCraftUnionDTO.getSysFileHisList() != null && mesCraftUnionDTO.getSysFileHisList().size() > 0) {
            List<MesDocument> mesDocumentList = new ArrayList<>();
            for (int i = 0; i < mesCraftUnionDTO.getSysFileHisList().size(); i++) {
                MesDocument mesDocument = new MesDocument();
                mesDocument.setMesId(mesCraftUnionDTO.getId());
                mesDocument.setDocumentId(mesCraftUnionDTO.getSysFileHisList().get(i).getId());
                mesDocument.setMesType(Const.FileType.BACK_FILE);
                mesDocumentList.add(mesDocument);
            }
            mesDocumentService.saveBatch(mesDocumentList);
        }
    }

    public void deleteChildren(MesCraftDTO mesCraftDTO) {
        // 获取工艺工序集合
        List<MesCraftProcessRef> list = processRefService.list(new QueryWrapper<MesCraftProcessRef>().eq("craft_id", mesCraftDTO.getId()));
        // 遍历工艺工序，删除工艺工序下的：班组集合/设备组对象<含设备组测点集合，设备组检测项集合>
        // 工序投料&工序产出集合&工艺工序工装集合&SOP附件集合
        for (int i = 0; i < list.size(); i++) {
            MesCraftProcessRef mesCraftProcessRef = list.get(i);
            // 删除班组
            carftTeamUserService.remove(new QueryWrapper<MesCarftTeamUser>().eq("craft_process_id", mesCraftProcessRef.getId()));
            // 删除设备组
            List<MesCraftDevice> mesCraftDeviceList = craftDeviceService.list(new QueryWrapper<MesCraftDevice>().eq("craft_process_id", mesCraftProcessRef.getId()));
            for (int j = 0; j < mesCraftDeviceList.size(); j++) {
                MesCraftDevice mesCraftDevice = mesCraftDeviceList.get(j);
                // 删除设备组测点集合
                mesProcessTestpointService.remove(new QueryWrapper<MesProcessTestpoint>().eq("craft_device_id", mesCraftDevice.getId()));
                // 删除设备组检测项集合
                mesProcessTestpointService.remove(new QueryWrapper<MesProcessTestpoint>().eq("craft_device_id", mesCraftDevice.getId()));
            }
            craftDeviceService.remove(new QueryWrapper<MesCraftDevice>().eq("craft_process_id", mesCraftProcessRef.getId()));
            // 删除工序投料&工序产出集合
            craftMaterialRefService.remove(new QueryWrapper<MesCraftMaterialRef>().eq("craft_process_id", mesCraftProcessRef.getId()));
            // 删除SOP附件集合
            mesDocumentService.remove(new QueryWrapper<MesDocument>().eq("mes_id", mesCraftProcessRef.getId()));
        }
        processRefService.remove(new QueryWrapper<MesCraftProcessRef>().eq("craft_id", mesCraftDTO.getId()));
    }

    public void saveChildren(MesCraftDTO mesCraftDTO) {
        // 解析工序对象集合
        if (mesCraftDTO.getMesCraftProcessRefDTOList().size() > 0) {
            for (int i = 0; i < mesCraftDTO.getMesCraftProcessRefDTOList().size(); i++) {
                MesCraftProcessRefDTO mesCraftUnionDTO = mesCraftDTO.getMesCraftProcessRefDTOList().get(i);
                // 解析工艺工序
                MesCraftProcessRef ref = new MesCraftProcessRef();
                BeanUtil.copyProperties(mesCraftUnionDTO, ref);
                ref.setCraftId(mesCraftDTO.getId());
                processRefService.save(ref);
                // 解析班组对象
                if (mesCraftUnionDTO.getTeamUserRefList().size() > 0) {
                    for (int j = 0; j < mesCraftUnionDTO.getTeamUserRefList().size(); j++) {
                        MesCarftTeamUser mesTeamUserRef = mesCraftUnionDTO.getTeamUserRefList().get(j);
                        mesTeamUserRef.setCraftProcessId(ref.getId());
                        carftTeamUserService.save(mesTeamUserRef);
                    }
                }
                // 解析设备组对象
                if (mesCraftUnionDTO.getCraftDeviceList().size() > 0) {
                    for (int j = 0; j < mesCraftUnionDTO.getCraftDeviceList().size(); j++) {
                        MesCraftDevice craftDevice = mesCraftUnionDTO.getCraftDeviceList().get(j);
                        craftDevice.setCraftProcessId(ref.getId());
                        craftDeviceService.save(craftDevice);
                        // 解析设备组的检测项集合
                        if (craftDevice.getCraftCheckRefList().size() > 0) {
                            for (int k = 0; k < craftDevice.getCraftCheckRefList().size(); k++) {
                                MesCraftCheckRef mesCraftCheckRef = craftDevice.getCraftCheckRefList().get(k);
                                mesCraftCheckRef.setCraftDeviceId(craftDevice.getId());
                                craftCheckRefService.save(mesCraftCheckRef);
                            }
                        }
                        // 解析设备组的测点集合
                        if (craftDevice.getProcessTestpointList().size() > 0) {
                            for (int k = 0; k < craftDevice.getProcessTestpointList().size(); k++) {
                                MesProcessTestpoint mesProcessTestpoint = craftDevice.getProcessTestpointList().get(k);
                                mesProcessTestpoint.setCraftDeviceId(craftDevice.getId());
                                mesProcessTestpointService.save(mesProcessTestpoint);
                            }
                        }
                    }
                }
                // 解析工序投料&工序产出 投料/产出 1-投料 2-产出
                if (mesCraftUnionDTO.getMaterialRefList().size() > 0) {
                    for (int j = 0; j < mesCraftUnionDTO.getMaterialRefList().size(); j++) {
                        MesCraftMaterialRef craftMaterialRef = mesCraftUnionDTO.getMaterialRefList().get(j);
                        craftMaterialRef.setCraftProcessId(ref.getId());
                        craftMaterialRefService.save(craftMaterialRef);
                    }
                }
                // 解析工艺工序工装
                if (mesCraftUnionDTO.getMaterialList().size() > 0) {
                    for (int j = 0; j < mesCraftUnionDTO.getMaterialList().size(); j++) {
                        MesCraftMaterial mesCraftMaterial = mesCraftUnionDTO.getMaterialList().get(j);
                        mesCraftMaterial.setCraftProcessId(ref.getId());
                        mesCraftMaterialService.save(mesCraftMaterial);
                    }
                }
                // 解析SOP文件对象
                if(mesCraftUnionDTO.getSysFileHisList().size() > 0){
                    mesCraftUnionDTO.setId(ref.getId());
                    this.saveMesCraftDocumentList(mesCraftUnionDTO);
                }
            }
        }
    }



    @Override
    public JSONObject importExcel(MultipartFile multipartFile) throws IOException {
        // 初始化错误行信息list，用来记录导入失败的rowNum
        List<ExcelErrRowDTO> errRowDOs = new ArrayList<>();

        // 对excel是否为空进行check
        if (multipartFile.isEmpty()) {
            throw new BDException("导入失败，请选择文件！");
        }

        //设置excel参数
        ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        List<MesCraftImportDTO> mesCraftImportDTOList;
        List<MesCraft> mesCrafts = CollectionUtil.newArrayList();

        JSONObject result = new JSONObject();

        // 解析excel中的行
        try {
            // 解析excel
            mesCraftImportDTOList = ExcelImportUtil.importExcel(multipartFile.getInputStream(), MesCraftImportDTO.class, params);
        } catch (Exception e) {
            throw new BDException("导入失败，文件内容解析错误！");
        }

        //取出db中所有重复的name
        List<String> dbNames = this.getAllName();//获取系统中所有的name
        List<String> duplicateNames = new ArrayList<>(); // 存放存在重复的name，用于定位重复存放存在重复的name的行

        if (dbNames.size() > 0 ) {
            duplicateNames = ExcelUtils.getDuplicateElements(dbNames);//取出存在重复的name
        }

        List<String> dbCodes = this.getAllCode();//获取系统中所有的code
        List<String> duplicateCodes = new ArrayList<>();
        if (dbCodes.size() > 0 ) {
            duplicateCodes = ExcelUtils.getDuplicateElements(dbCodes);
        }

        List<SysUser> sysUserList = sysUserService.list();
        Map<String,Integer> userMap = sysUserList.stream().collect(Collectors.toMap(SysUser::getRealName,SysUser::getId,(v1, v2) -> v2));

        // 班组人员map
        List<MesTeamUserRef> teamUserRefList = mesTeamUserRefService.list();
        Map<Integer, Integer> teamUserRefMap = teamUserRefList.stream()
                .collect(Collectors.toMap(MesTeamUserRef::getUserId, MesTeamUserRef::getTeamId, (v1, v2) -> v2));

        // 工序
        List<MesProcess> processList = mesProcessService.list();
        Map<String,Integer> processMap = processList.stream().collect(Collectors.toMap(MesProcess::getProcessName,MesProcess::getId,(v1,v2)->v2));


        //校验
        if (mesCraftImportDTOList.size() > 0) {

            int index = 1;
            for (MesCraftImportDTO mesCraftImportDTO : mesCraftImportDTOList) {
                index ++;
                // check
                StringBuilder stringBuilder = new StringBuilder();
                ExcelErrRowDTO excelErrRowDO= new ExcelErrRowDTO();

                // 参数校验
                stringBuilder.append(ValidatorUtils.validateExcel(mesCraftImportDTO));

                // 检验Name 是否重复
                if(duplicateNames.contains(mesCraftImportDTO.getCraftName())){
                    stringBuilder.append("工艺名称已经存在，请勿重复！");
                }
                // code 是否重复
                if(duplicateCodes.contains(mesCraftImportDTO.getCraftNo())){
                    stringBuilder.append("工艺编号已经存在，请勿重复！");
                }
                List<Integer> userIdList = new ArrayList<>();
                mesCraftImportDTO.setTeamUserList(userIdList);//取消班组限制
                if (org.apache.commons.lang3.StringUtils.isBlank(mesCraftImportDTO.getTeamUser())) mesCraftImportDTO.setTeamUser("");
                for (String s : mesCraftImportDTO.getTeamUser().split(",")) {
                    if (org.apache.commons.lang3.StringUtils.isBlank(s)) continue;
                    userMap.get(s);
                    Integer  userId = userMap.get(s);
                    if(userId==null){
                        stringBuilder.append("人员:"+s+",在系统中不存在！");
                        continue;
                    }
                    userIdList.add(userId);
                }

                Integer processId = processMap.get(mesCraftImportDTO.getProcessName());
                if(processId==null){
                    stringBuilder.append("工序:"+mesCraftImportDTO.getProcessName()+",在系统中不存在！");
                }
                mesCraftImportDTO.setProcessId(processId);

                // 将错误行信息保存到list
                String errMsg = stringBuilder.toString();
                if(StringUtils.isNotEmpty(errMsg)){
                    excelErrRowDO.setRowIndex(index);
                    excelErrRowDO.setErrMessage(errMsg);
                    errRowDOs.add(excelErrRowDO);
                    continue;
                }
                //保存
                MesCraft mesCraft = new MesCraft();
                BeanUtils.copyProperties(mesCraftImportDTO,mesCraft);
                mesCrafts.add(mesCraft);

            }

            if(errRowDOs.size()==0){
                //取出工艺路线的主体
                Map<String,MesCraft> craftSaveMap = mesCrafts.stream().collect(Collectors.toMap(MesCraft::getCraftName, Function.identity(),(v1, v2) -> v2));
                List<MesCraft> saveList = craftSaveMap.entrySet().stream().map(entry -> entry.getValue()).collect(Collectors.toList());
                saveBatch(saveList);
                Map<String,Integer> craftMap = saveList.stream().collect(Collectors.toMap(MesCraft::getCraftName,MesCraft::getId,(v1, v2) -> v2));

                List<MesCraftProcessRef> mesCraftProcessRefList = new ArrayList<>();
                for (MesCraftImportDTO craftImportDTO : mesCraftImportDTOList) {
                    // 解析工艺工序
                    MesCraftProcessRef ref = new MesCraftProcessRef();
                    ref.setBasicSecond(craftImportDTO.getProcessTime());
                    ref.setProcessId(craftImportDTO.getProcessId());
                    ref.setSortNo(craftImportDTO.getSortNo());
                    ref.setCraftId(craftMap.get(craftImportDTO.getCraftName()));
                    mesCraftProcessRefList.add(ref);
                }
                processRefService.saveBatch(mesCraftProcessRefList);

                List<MesCarftTeamUser> ctuList = new ArrayList<>();
                Map<String,Integer> cpMap = mesCraftProcessRefList.stream().collect(Collectors.toMap(x->x.getProcessId()+"_"+x.getCraftId(),MesCraftProcessRef::getId,(v1, v2) -> v2));
                for (MesCraftImportDTO craftImportDTO : mesCraftImportDTOList) {
                    // 保存班组
                    if (ObjectUtil.isEmpty(craftImportDTO.getTeamUserList())) continue;
                    Integer craftProcessId = cpMap.get(craftImportDTO.getProcessId()+"_"+craftMap.get(craftImportDTO.getCraftName()));
                    for (Integer userId : craftImportDTO.getTeamUserList()) {
                        MesCarftTeamUser mesTeamUserRef = new MesCarftTeamUser();
                        mesTeamUserRef.setCraftProcessId(craftProcessId);
                        mesTeamUserRef.setUserId(userId);
                        mesTeamUserRef.setTeamId(teamUserRefMap.get(userId));
                        ctuList.add(mesTeamUserRef);
                    }
                }
                carftTeamUserService.saveBatch(ctuList);
            }
            // 导出错误行
            String errFileUrl = ExcelUtils.exportErrRows(errRowDOs,multipartFile,sysFileHisService);
            result.put("errFileUrl",errFileUrl);
        }
        return result;
    }

    private List<String> getAllCode() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("craft_no");
        List<MesCraft> craftList = this.list();
        List<String> codes = craftList.stream().map(MesCraft::getCraftNo).collect(Collectors.toList());
        return codes;
    }

    private List<String> getAllName() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("craft_name");
        List<MesCraft> craftList = this.list();
        List<String> names = craftList.stream().map(MesCraft::getCraftName).collect(Collectors.toList());
        return names;
    }
}




